﻿using System;
using System.Collections.Generic;
using Assist;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.UI;
using YArchitech.Controls;
using YArchitech.Revit;
using YJKArchMethodLibrary.Utils;
using YJKCodeBase.WinForm;
using YJKElementFinish.ColumnSurface.DataDefinition;
using YJKElementFinish.ColumnSurface.Managers;
using TopologySearch;

namespace YJKElementFinish.ColumnSurface.Controllers
{
	public class AddSurfaceLayersController
	{
		public AddSurfaceLayersController(ExternalCommandData cmdData)
		{
			this.m_ComdData = cmdData;
			this.m_UIApp = cmdData.Application;
			this.m_UIDoc = this.m_UIApp.ActiveUIDocument;
			this.m_App = this.m_UIApp.Application;
			this.m_Doc = this.m_UIDoc.Document;
		}

		public static int GetRefCurvesCount(Document doc)
		{
			List<ReferenceCurveInfo> list = new List<ReferenceCurveInfo>();
			AddSurfaceLayersController.GetRefCurves(doc, ref list);
			return list.Count;
		}

		public Result AddSurfaceByRefCurve(List<WallTypeLayerInfos> currentWallTypeLayerInfo)
		{
			List<ReferenceCurveInfo> refCurves = new List<ReferenceCurveInfo>();
			AddSurfaceLayersController.GetRefCurves(this.m_Doc, ref refCurves);
			if (!this.GetWallInfosByRefCurve(ref refCurves))
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			List<ColumnEdgeLoopInfo> currentLayerColumnInfos = new List<ColumnEdgeLoopInfo>();
			if (!this.GetColumnInfosByRefCurve(ref refCurves, ref currentLayerColumnInfos))
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			this.CreateOffsetWalls(refCurves, currentLayerColumnInfos, currentWallTypeLayerInfo);
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		public Result AddSurfaceByRefCurve(ref List<OffsetWallInfo> lstOffsetWallInfo, WallType wallType, List<ElementId> lstRefCurveId)
		{
			List<ReferenceCurveInfo> refCurves = new List<ReferenceCurveInfo>();
			this.GetRefCurves(ref refCurves, lstRefCurveId);
			if (!this.GetWallInfosByRefCurve(ref refCurves))
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			List<ColumnEdgeLoopInfo> currentLayerColumnInfos = new List<ColumnEdgeLoopInfo>();
			if (!this.GetColumnInfosByRefCurve(ref refCurves, ref currentLayerColumnInfos))
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			this.CreateOffsetWalls(ref lstOffsetWallInfo, refCurves, currentLayerColumnInfos, wallType);
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		public bool SelectExternalProfile(ref List<Curve> selFaceProfile)
		{
			bool result;
			try
			{
				List<Wall> list = new List<Wall>();
				WallCommon.GetWalls(this.m_Doc, ref list);
				List<FamilyInstance> list2 = new List<FamilyInstance>();
				ColumnCommon.GetColumns(this.m_Doc, ref list2);
				List<Solid> list3 = new List<Solid>();
				foreach (Wall element in list)
				{
					List<Solid> elementSolids = ElementCommon.GetElementSolids(this.m_UIApp, element);
					list3.AddRange(elementSolids);
				}
				foreach (FamilyInstance element2 in list2)
				{
					List<Solid> elementSolids2 = ElementCommon.GetElementSolids(this.m_UIApp, element2);
					list3.AddRange(elementSolids2);
				}
				CurveArray curveArray = new CurveArray();
				ElementCommon.GetSolidProjection(this.m_Doc, list3, ref curveArray);
				List<Pole2D> list4 = new List<Pole2D>();
				foreach (object obj in curveArray)
				{
					Curve curve = (Curve)obj;
					Pole2D item = Pole2D.TransformWallToStructure2DPole(curve, ElementId.InvalidElementId, 0.0, 0.0);
					list4.Add(item);
				}
				StructureLoopSearcher structureLoopSearcher = new StructureLoopSearcher(this.m_ComdData, 0.001);
				List<List<Curve>> fullFloorEdgeLoops = structureLoopSearcher.GetFullFloorEdgeLoops(list4, StructureLoopSearcher.SearchEdgeLocation.SEL_Outside);
				foreach (List<Curve> collection in fullFloorEdgeLoops)
				{
					selFaceProfile.AddRange(collection);
				}
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		public bool SelectRoomProfile(ref List<Curve> selFaceProfile, bool bIncludeColumn = true)
		{
			bool result;
			try
			{
				IList<Reference> list = this.m_UIDoc.Selection.PickObjects(Autodesk.Revit.UI.Selection.ObjectType.Element, new YJKElementFinish.ColumnSurface.Managers.RoomFilter(), "请选择房间：");
				List<Element> list2 = new List<Element>();
				foreach (Reference reference in list)
				{
					Element element = this.m_Doc.GetElement(reference);
					list2.Add(element);
				}
				result = this.SelectRoomProfile(ref selFaceProfile, list2, bIncludeColumn);
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		public bool SelectRoomProfile(ref List<Curve> lstCurveFaceProfile, List<Element> lstSelectRooms, bool bIncludeColumn = true)
		{
			foreach (Element element in lstSelectRooms)
			{
				Room room = element as Room;
				IList<IList<BoundarySegment>> boundarySegments = room.GetBoundarySegments(new SpatialElementBoundaryOptions());
				foreach (IList<BoundarySegment> list in boundarySegments)
				{
					foreach (BoundarySegment segment in list)
					{
						if (segment.GetElement(this.m_Doc) == null)
						{
							lstCurveFaceProfile.Add(segment.GetCurve());
						}
						else if (segment.GetElement(this.m_Doc).GetType() == typeof(Wall))
						{
							Wall wall = segment.GetElement(this.m_Doc) as Wall;
							if (wall != null)
							{
								lstCurveFaceProfile.Add(segment.GetCurve());
							}
						}
						else if (segment.GetElement(this.m_Doc).GetType() == typeof(FamilyInstance) && bIncludeColumn)
						{
							FamilyInstance familyInstance = segment.GetElement(this.m_Doc) as FamilyInstance;
							if (familyInstance != null && (familyInstance.Category.Id.IntegerValue == -2000100 || familyInstance.Category.Id.IntegerValue == -2001330))
							{
								lstCurveFaceProfile.Add(segment.GetCurve());
							}
						}
					}
				}
			}
			return true;
		}

		private static void GetRefCurves(Document doc, ref List<ReferenceCurveInfo> refCurves)
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(doc, doc.ActiveView.Id);
			ICollection<Element> collection = filteredElementCollector.OfClass(typeof(CurveElement)).ToElements();
			foreach (Element element in collection)
			{
				if (!(element.GetType() != typeof(DetailLine)) || !(element.GetType() != typeof(DetailArc)))
				{
					DetailCurve detailCurve = element as DetailCurve;
					if (detailCurve.LineStyle.Name.IndexOf(RefCurveController.m_StrLineNamePrefix) != -1)
					{
						Curve curve = detailCurve.GeometryCurve;
						XYZ endPoint = curve.GetEndPoint(0);
						XYZ xyz = new XYZ(0.0, 0.0, -endPoint.Z);
						Transform transform = Transform.CreateTranslation(xyz);
						curve = RevitVersionFuncs.CreateTransformed(transform, curve);
						ReferenceCurveInfo item = new ReferenceCurveInfo(curve, element.Id);
						refCurves.Add(item);
					}
				}
			}
		}

		private void GetRefCurves(ref List<ReferenceCurveInfo> refCurves, List<ElementId> lstRefCurveId)
		{
			foreach (ElementId elementId in lstRefCurveId)
			{
				Element elementById = this.m_Doc.GetElementById(elementId);
				if (elementById != null && (!(elementById.GetType() != typeof(DetailLine)) || !(elementById.GetType() != typeof(DetailArc))))
				{
					DetailCurve detailCurve = elementById as DetailCurve;
					if (detailCurve.LineStyle.Name.IndexOf(RefCurveController.m_StrLineNamePrefix) != -1)
					{
						Curve curve = detailCurve.GeometryCurve;
						XYZ endPoint = curve.GetEndPoint(0);
						XYZ xyz = new XYZ(0.0, 0.0, -endPoint.Z);
						Transform transform = Transform.CreateTranslation(xyz);
						curve = RevitVersionFuncs.CreateTransformed(transform, curve);
						ReferenceCurveInfo item = new ReferenceCurveInfo(curve, elementById.Id);
						refCurves.Add(item);
					}
				}
			}
		}

		private bool GetWallInfosByRefCurve(ref List<ReferenceCurveInfo> refCurves)
		{
			bool result;
			try
			{
				List<WallGeometryInfo> list = new List<WallGeometryInfo>();
				FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_Doc, this.m_Doc.ActiveView.Id);
				ICollection<Element> collection = filteredElementCollector.OfClass(typeof(Wall)).ToElements();
				foreach (Element element in collection)
				{
					Wall wall = element as Wall;
					List<Solid> elementSolids = ElementCommon.GetElementSolids(this.m_UIApp, wall);
					CurveArray projection = new CurveArray();
					ElementCommon.GetSolidProjection(this.m_Doc, elementSolids, ref projection);
					WallGeometryInfo item = new WallGeometryInfo(wall, projection);
					list.Add(item);
				}
				foreach (ReferenceCurveInfo referenceCurveInfo in refCurves)
				{
					Curve theCurve = referenceCurveInfo.TheCurve;
					List<Wall> wallByRefCurve = this.GetWallByRefCurve(theCurve, list);
					foreach (Wall wall2 in wallByRefCurve)
					{
						referenceCurveInfo.AddRefWall(wall2);
					}
				}
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		private bool GetColumnInfosByRefCurve(ref List<ReferenceCurveInfo> refCurves, ref List<ColumnEdgeLoopInfo> currentLayerColumnInfos)
		{
			bool result;
			try
			{
				FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_Doc, this.m_Doc.ActiveView.Id);
				ICollection<Element> collection = filteredElementCollector.OfCategory(BuiltInCategory.OST_Columns).OfClass(typeof(FamilyInstance)).ToElements();
				foreach (Element element in collection)
				{
					FamilyInstance column = element as FamilyInstance;
					ColumnEdgeLoopInfo item = ColumnEdgeLoopInfo.CreateByColumn(this.m_UIApp, column);
					currentLayerColumnInfos.Add(item);
				}
				new List<ColumnEdgeLoopInfo>();
				FilteredElementCollector filteredElementCollector2 = new FilteredElementCollector(this.m_Doc, this.m_Doc.ActiveView.Id);
				ICollection<Element> collection2 = filteredElementCollector2.OfCategory(BuiltInCategory.OST_StructuralColumns).OfClass(typeof(FamilyInstance)).ToElements();
				foreach (Element element2 in collection2)
				{
					FamilyInstance column2 = element2 as FamilyInstance;
					ColumnEdgeLoopInfo item2 = ColumnEdgeLoopInfo.CreateByColumn(this.m_UIApp, column2);
					currentLayerColumnInfos.Add(item2);
				}
				foreach (ReferenceCurveInfo referenceCurveInfo in refCurves)
				{
					Curve theCurve = referenceCurveInfo.TheCurve;
					List<FamilyInstance> columnByRefCurve = this.GetColumnByRefCurve(theCurve, currentLayerColumnInfos);
					foreach (FamilyInstance column3 in columnByRefCurve)
					{
						referenceCurveInfo.AddRefColumn(column3);
					}
				}
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		private List<Wall> GetWallByRefCurve(Curve detailCurve, List<WallGeometryInfo> CurrentLayerWallInfos)
		{
			List<Wall> list = new List<Wall>();
			foreach (WallGeometryInfo wallGeometryInfo in CurrentLayerWallInfos)
			{
				if (wallGeometryInfo.IsWallFace(detailCurve))
				{
					list.Add(wallGeometryInfo.Component);
				}
			}
			return list;
		}

		private List<FamilyInstance> GetColumnByRefCurve(Curve detailCurve, List<ColumnEdgeLoopInfo> CurrentLayerColumnInfos)
		{
			List<FamilyInstance> list = new List<FamilyInstance>();
			foreach (ColumnEdgeLoopInfo columnEdgeLoopInfo in CurrentLayerColumnInfos)
			{
				if (columnEdgeLoopInfo.IsColumnFace(detailCurve))
				{
					list.Add(columnEdgeLoopInfo.Component);
				}
			}
			return list;
		}

		private void GetOffsetReferenceInfos(Pole2D pole, double offset, ReferenceCurveInfo refCurveInfo, List<ColumnEdgeLoopInfo> currentLayerColumnInfos, ref List<OffsetReferenceInfo> offsetLoopInfos)
		{
			try
			{
				Curve curve = pole.NegativeCurve();
				XYZ xyz = curve.Evaluate(0.5, true);
				Curve curve2 = pole.PositiveCurve();
				XYZ xyz2 = curve2.Evaluate(0.5, true);
				if (refCurveInfo.RefWalls.Count > 0)
				{
					Wall wall = this.SelecteRefWall(refCurveInfo.RefWalls, refCurveInfo.TheCurve);
					Pole2D referencePole = new Pole2D(wall.Id, pole.StartPoint, pole.EndPoint, pole.Bulge, pole.PositiveStartPoint, pole.PositiveEndPoint, pole.NegativeStartPoint, pole.NegativeEndPoint, pole.IsPositiveDirection);
					OffsetReferenceInfo offsetReferenceInfo = new OffsetReferenceInfo(referencePole, null, null);
					Curve curve3 = (wall.Location as LocationCurve).Curve;
					if (this.IsParallel(curve3, refCurveInfo.TheCurve))
					{
						double val = curve3.Distance(xyz);
						double val2 = curve3.Distance(xyz2);
						if (Geometry.LessThan(val2, val))
						{
							offsetReferenceInfo.OffsetNegativeBaseline = curve;
						}
						else
						{
							offsetReferenceInfo.OffsetPositiveBaseline = curve2;
						}
						offsetLoopInfos.Add(offsetReferenceInfo);
					}
					else
					{
						XYZ xyz3 = curve3.Evaluate(0.5, true);
						double val3 = xyz3.DistanceTo(xyz);
						double val4 = xyz3.DistanceTo(xyz2);
						if (Geometry.LessThan(val4, val3))
						{
							offsetReferenceInfo.OffsetNegativeBaseline = curve;
						}
						else
						{
							offsetReferenceInfo.OffsetPositiveBaseline = curve2;
						}
						offsetLoopInfos.Add(offsetReferenceInfo);
					}
				}
				else if (refCurveInfo.RefColumns.Count > 0)
				{
					FamilyInstance column = refCurveInfo.RefColumns[0];
					Pole2D referencePole2 = new Pole2D(column.Id, pole.StartPoint, pole.EndPoint, pole.Bulge, pole.PositiveStartPoint, pole.PositiveEndPoint, pole.NegativeStartPoint, pole.NegativeEndPoint, pole.IsPositiveDirection);
					OffsetReferenceInfo offsetReferenceInfo2 = new OffsetReferenceInfo(referencePole2, null, null);
					int num = currentLayerColumnInfos.FindIndex((ColumnEdgeLoopInfo item) => item.Component.Id.IntegerValue == column.Id.IntegerValue);
					if (num != -1)
					{
						ColumnEdgeLoopInfo columnEdgeLoopInfo = currentLayerColumnInfos[num];
						if (!columnEdgeLoopInfo.IsInside(xyz, true))
						{
							offsetReferenceInfo2.OffsetNegativeBaseline = curve;
						}
						else
						{
							offsetReferenceInfo2.OffsetPositiveBaseline = curve2;
						}
					}
					offsetLoopInfos.Add(offsetReferenceInfo2);
				}
			}
			catch (Exception)
			{
			}
		}

		private Wall SelecteRefWall(List<Wall> refWalls, Curve refCurve)
		{
			foreach (Wall wall in refWalls)
			{
				Curve curve = (wall.Location as LocationCurve).Curve;
				if (this.IsParallel(curve, refCurve))
				{
					return wall;
				}
			}
			return refWalls[0];
		}

		private bool IsParallel(Curve curve1, Curve curve2)
		{
			if (curve1.GetType() != curve2.GetType())
			{
				return false;
			}
			if (curve1.GetType() == typeof(Line))
			{
				XYZ a = curve1.GetEndPoint(0) - curve1.GetEndPoint(1);
				XYZ b = curve2.GetEndPoint(0) - curve2.GetEndPoint(1);
				return Geometry.IsParallel(a, b, 1E-09);
			}
			if (curve1.GetType() == typeof(Arc))
			{
				XYZ center = ((Arc)curve1).Center;
				XYZ center2 = ((Arc)curve2).Center;
				return Geometry.IsEqual(center, center2, 0.032);
			}
			return false;
		}

		private void CreateOffsetWalls(ref List<OffsetWallInfo> lstOffsetWallInfo, List<ReferenceCurveInfo> refCurves, List<ColumnEdgeLoopInfo> currentLayerColumnInfos, WallType wallType)
		{
			try
			{
				double offset = wallType.Width / 2.0;
				List<Pole2D> list = new List<Pole2D>();
				this.GetOffsetWallInfos(refCurves, offset, ref list);
				StructureLoopSearcher structureLoopSearcher = new StructureLoopSearcher(this.m_ComdData);
				structureLoopSearcher.FormatDoubleLine(ref list);
				List<OffsetReferenceInfo> realOffsetLoopInfos = new List<OffsetReferenceInfo>();
				using (List<Pole2D>.Enumerator enumerator = list.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						Pole2D pole = enumerator.Current;
						int num = refCurves.FindIndex((ReferenceCurveInfo item) => item.CurveId.IntegerValue == pole.ComponentId.IntegerValue);
						if (num != -1)
						{
							ReferenceCurveInfo refCurveInfo = refCurves[num];
							this.GetOffsetReferenceInfos(pole, offset, refCurveInfo, currentLayerColumnInfos, ref realOffsetLoopInfos);
						}
					}
				}
				this.CreateWalls(realOffsetLoopInfos, wallType, ref lstOffsetWallInfo);
			}
			catch (Exception ex)
			{
				YJKMessageBox.Show(ex.Message);
			}
		}

		private void CreateOffsetWalls(List<ReferenceCurveInfo> refCurves, List<ColumnEdgeLoopInfo> currentLayerColumnInfos, List<WallTypeLayerInfos> surfaceLayerInfosList)
		{
			List<OffsetWallInfo> offsetWallInfoList = new List<OffsetWallInfo>();
			TransactionGroup transactionGroup = new TransactionGroup(this.m_Doc);
			transactionGroup.Start("create offset wall");
			try
			{
				double num = 0.0;
				foreach (WallTypeLayerInfos wallTypeLayerInfos in surfaceLayerInfosList)
				{
					double width = wallTypeLayerInfos.Width;
					num += width / 2.0;
					List<CompoundStructureLayer> list = new List<CompoundStructureLayer>();
					foreach (WallLayerInfos wallLayerInfos in wallTypeLayerInfos.LayerList)
					{
						list.Add(wallLayerInfos.StructureLayer);
					}
					Transaction transaction = new Transaction(this.m_Doc);
					transaction.Start("create wall type");
					WallType wallType = null;
					try
					{
						wallType = WallTypeManager.GetWallType(wallTypeLayerInfos.TypeName, null, list, this.m_Doc, false);
						transaction.Commit();
					}
					catch (Exception)
					{
						transaction.RollBack();
						num += width / 2.0;
						continue;
					}
					if (wallType == null)
					{
						num += width / 2.0;
					}
					else
					{
						List<Pole2D> list2 = new List<Pole2D>();
						this.GetOffsetWallInfos(refCurves, num, ref list2);
						StructureLoopSearcher structureLoopSearcher = new StructureLoopSearcher(this.m_ComdData);
						structureLoopSearcher.FormatDoubleLine(ref list2);
						List<OffsetReferenceInfo> realOffsetLoopInfos = new List<OffsetReferenceInfo>();
						using (List<Pole2D>.Enumerator enumerator3 = list2.GetEnumerator())
						{
							while (enumerator3.MoveNext())
							{
								Pole2D pole = enumerator3.Current;
								int num2 = refCurves.FindIndex((ReferenceCurveInfo item) => item.CurveId.IntegerValue == pole.ComponentId.IntegerValue);
								if (num2 != -1)
								{
									ReferenceCurveInfo refCurveInfo = refCurves[num2];
									this.GetOffsetReferenceInfos(pole, num, refCurveInfo, currentLayerColumnInfos, ref realOffsetLoopInfos);
								}
							}
						}
						transaction = new Transaction(this.m_Doc);
						transaction.Start("create wall");
						try
						{
							this.CreateWalls(realOffsetLoopInfos, wallType, ref offsetWallInfoList);
							transaction.Commit();
						}
						catch (Exception)
						{
							transaction.RollBack();
							continue;
						}
						num += width / 2.0;
					}
				}
				transactionGroup.Commit();
				WallCommon.JoinWalls(offsetWallInfoList, this.m_Doc, false);
			}
			catch (Exception)
			{
				if (transactionGroup != null)
				{
					transactionGroup.RollBack();
				}
			}
		}

		private void GetOffsetWallInfos(List<ReferenceCurveInfo> refCurves, double offset, ref List<Pole2D> poleList)
		{
			foreach (ReferenceCurveInfo referenceCurveInfo in refCurves)
			{
				Pole2D item = Pole2D.TransformWallToStructure2DPole(referenceCurveInfo.TheCurve, referenceCurveInfo.CurveId, offset, offset);
				poleList.Add(item);
			}
		}

		private void CreateWalls(List<OffsetReferenceInfo> realOffsetLoopInfos, WallType wallType, ref List<OffsetWallInfo> offsetWallInfoList)
		{
			using (List<OffsetReferenceInfo>.Enumerator enumerator = realOffsetLoopInfos.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					OffsetReferenceInfo info = enumerator.Current;
					try
					{
						int num = offsetWallInfoList.FindIndex((OffsetWallInfo item) => item.ReferencePole.SameAs(info.ReferencePole));
						OffsetWallInfo offsetWallInfo;
						if (num == -1)
						{
							offsetWallInfo = new OffsetWallInfo(info.ReferencePole);
							offsetWallInfoList.Add(offsetWallInfo);
						}
						else
						{
							offsetWallInfo = offsetWallInfoList[num];
						}
						double height = 0.0;
						Element element = this.m_Doc.GetElement(info.ReferencePole.ComponentId);
						if (element.GetType() == typeof(Wall))
						{
							Wall wall = element as Wall;
							double num2 = 0.0;
							WallCommon.GetWallElevationInfo(wall, this.m_Doc, ref num2, ref height);
						}
						else
						{
							FamilyInstance column = element as FamilyInstance;
							double num3 = 0.0;
							ColumnCommon.GetColumnElevationInfo(column, this.m_Doc, ref num3, ref height);
						}
						if (info.OffsetNegativeBaseline != null)
						{
							Wall wall2 = WallCommon.CreateWall(this.m_Doc, info.OffsetNegativeBaseline, wallType, height);
							wall2.Flip();
							offsetWallInfo.AddNegativeWalls(wall2);
						}
						if (info.OffsetPositiveBaseline != null)
						{
							Wall newWall = WallCommon.CreateWall(this.m_Doc, info.OffsetPositiveBaseline, wallType, height);
							offsetWallInfo.AddPositiveWalls(newWall);
						}
					}
					catch (Exception ex)
					{
						string message = ex.Message;
					}
				}
			}
		}

		private ExternalCommandData m_ComdData;

		private UIApplication m_UIApp;

		private UIDocument m_UIDoc;

		private Autodesk.Revit.ApplicationServices.Application m_App;

		private Document m_Doc;

		public static WindowHandle _hWndRevit;
	}
}
